// d3d_image.cpp
//

#include "../tr_local.h"
#include "../DXT/DXTCodec.h"


idImage::idImage() {
	textureHandle = NULL;
	width = -1;
	height = -1;
	next = NULL;
}

idImage::~idImage() {
	Release();
}

/*
===========
idImage::Init
===========
*/
void idImage::Init( int width, int height, idImageInternalFormat_t format ) {
	D3D11_TEXTURE2D_DESC desc;

	width = width;
	height = height;

	_xcrop = _ycrop = 0;

	internalFormat = format;

	switch(format)
	{
#if 1
		case IMG_COMPRESSED_RGBA_S3TC_DXT5_EXT:
#endif
		case IMG_RGBA:

			desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			desc.Usage = D3D11_USAGE_DEFAULT;
			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
			desc.CPUAccessFlags = 0;
		break;
		case IMG_RGBA_RT:
			desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			desc.Usage = D3D11_USAGE_DEFAULT;
			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
			desc.CPUAccessFlags = 0;
		break;


		
#if 0
		case IMG_COMPRESSED_RGBA_S3TC_DXT5_EXT:
			desc.Format = DXGI_FORMAT_BC5_UNORM;
			desc.Usage = D3D11_USAGE_DEFAULT;
			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
			desc.CPUAccessFlags = 0;
		break;
#endif

		case IMG_DEPTH_STENCIL:
			desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
			desc.Usage = D3D11_USAGE_DEFAULT;
			desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
			desc.CPUAccessFlags = 0;
			break;

		default:
			Sys_Error("idImage::Init: Unknown format\n");
			break;
	}
    

	desc.Width = width;
	desc.Height = height;
	desc.MipLevels = 1;
    desc.ArraySize = 1;
	desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.MiscFlags = 0;

	tr.GetDevice()->CreateTexture2D( &desc, NULL, &textureHandle );
	if(textureHandle == NULL)
		Sys_Error("Failed to allocate texture");

	if(format != IMG_DEPTH_STENCIL)
	{
		D3D11_SHADER_RESOURCE_VIEW_DESC rv;

		rv.Format = desc.Format;
		rv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		rv.Texture2D.MostDetailedMip = 0;
		rv.Texture2D.MipLevels = 1;
		tr.GetDevice()->CreateShaderResourceView( textureHandle, &rv, &textureHandleRV );
		if( textureHandleRV== NULL)
			Sys_Error("Failed to allocate texture RV" );
	}

	    // Create the sample state
    D3D11_SAMPLER_DESC sampDesc;
	HRESULT hr;
	ZeroMemory( &sampDesc, sizeof(sampDesc) );
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    hr = tr.GetDevice()->CreateSamplerState( &sampDesc, &g_pSamplerLinear );
    if( FAILED( hr ) ) {
        Sys_Error("Failed to create texture sample state");
	}
}

/*
===========
idImage::UploadBuffer
===========
*/
void idImage::UploadBuffer( byte *buffer ) {
	D3D11_BOX destRegion;
	destRegion.left = _ycrop;
	destRegion.right = width;
	destRegion.top = _xcrop;
	destRegion.bottom = height;
	destRegion.front = 0;
	destRegion.back = 1;

	_xcrop = _ycrop = 0;

	if(internalFormat == IMG_COMPRESSED_RGBA_S3TC_DXT5_EXT)
	{
		byte *tempBuffer = new byte[width * height * 4];
		idDxtDecoder decoder;
		decoder.DecompressImageDXT5( buffer, tempBuffer, width, height );
		tr.GetDeviceContext()->UpdateSubresource( textureHandle, 0, &destRegion, tempBuffer, width* 4, 0 ); 
		delete tempBuffer;
	}
	else
	{
		tr.GetDeviceContext()->UpdateSubresource( textureHandle, 0, &destRegion, buffer, width * 4, 0 ); 
	}
}
/*
===========
idImage::UploadBuffer
===========
*/
void idImage::UploadBuffer( byte *buffer, float width, float height ) {
	D3D11_BOX destRegion;
	destRegion.left = _ycrop;
	destRegion.right = width;
	destRegion.top = _xcrop;
	destRegion.bottom = height;
	destRegion.front = 0;
	destRegion.back = 1;

	_xcrop = _ycrop = 0;

	if(internalFormat == IMG_COMPRESSED_RGBA_S3TC_DXT5_EXT)
	{
		byte *tempBuffer = new byte[width * height * 4];
		idDxtDecoder decoder;
		decoder.DecompressImageDXT5( buffer, tempBuffer, width, height );
		tr.GetDeviceContext()->UpdateSubresource( textureHandle, 0, &destRegion, tempBuffer, width* 4, 0 ); 
		delete tempBuffer;
	}
	else
	{
		tr.GetDeviceContext()->UpdateSubresource( textureHandle, 0, &destRegion, buffer, width * 4, 0 ); 
	}
}

/*
===========
idImage::Release
===========
*/
void idImage::Release( void ) {
	if( textureHandle == NULL )
		return;

	 textureHandle->Release();
	 textureHandle = NULL;
	width = -1;
	height = -1;
}

/*
===========
idImage::Resize
===========
*/
void idImage::Resize( int width, int height ) {
	Release();

	Init( width, height );
}

/*
===========
idImage::Bind
===========
*/
void idImage::Bind( int texNum ) {
	tr.GetDeviceContext()->PSSetShaderResources( texNum, 1, &textureHandleRV );
	tr.GetDeviceContext()->PSSetSamplers( texNum, 1, &g_pSamplerLinear );
}
/*
===============
R_DeleteTextures
===============
*/
void R_DeleteTextures( void ) {

}

/*
===============
R_PurgeImage
===============
*/
void R_PurgeImage( image_t *image ) {

	
}

/*
===============
GL_TextureMode
===============
*/
void GL_TextureMode( const char *string ) {
	int i;
	image_t *glt;

	for ( i = 0 ; i < 6 ; i++ ) {
		if ( !Q_stricmp( modes[i].name, string ) ) {
			break;
		}
	}

	// hack to prevent trilinear from being set on voodoo,
	// because their driver freaks...
	if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
		ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
		i = 3;
	}


	if ( i == 6 ) {
		ri.Printf( PRINT_ALL, "bad filter name\n" );
		return;
	}

	gl_filter_min = modes[i].minimize;
	gl_filter_max = modes[i].maximize;

	// change all the existing mipmap texture objects
	for ( i = 0 ; i < tr.numImages ; i++ ) {
		glt = tr.images[ i ];
		if ( glt->mipmap ) {
			GL_Bind( glt );
		//	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min );
			//qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max );
		}
	}
}